"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lei.chang on '25/09/2023'
    comment: 欧易平台对接
"""
import json
from enum import Enum
from datetime import datetime as dt
import time
import functools
import httpx

from okx.PublicData import PublicAPI
from okx.MarketData import MarketAPI
from okx.Account import AccountAPI
from okx.Trade import TradeAPI
from pydantic import BaseModel, Field

from config import Config
from project.core.exception import BizError


class OkexException(Exception):
    """
    """
    def __init__(self, code: str, msg: str):
        """
        """
        self.code = code
        self.msg = msg

    def __str__(self) -> str:
        return f"[{self.code}] {self.msg}"


def retry(count=5, interval=1):
    """ 方式执行失败重试次数
    :param count:
    :param interval: 重试间隔时间
    :return:
    """
    def handle_func(func):
        @functools.wraps(func)
        def wrap_func(*args, **kwargs):

            _count = 0
            while True:
                try:
                    ret = func(*args, **kwargs)
                    return ret

                except (OkexException, httpx.ConnectTimeout):
                    _count += 1
                    if interval > 0:
                        time.sleep(interval)

                    # 执行次数超过跳出
                    if _count >= count:
                        break

        return wrap_func

    return handle_func


class Inst(BaseModel):
    """ 交易产品
    """
    inst_id: str = Field('', title='产品id')
    inst_code: int = Field(0, title='产品编号')
    list_time: str = Field('', title='上线时间')
    state: str = Field('', title='产品状态', description='live(交易中)/suspend(暂停中)/preopen(预上线)/test(测试中)')

    @property
    def validity_period(self):
        """
        :return:
        """
        validity_period = 0
        if self.list_time:
            validity_period = (dt.now().date() - dt.fromtimestamp(int(self.list_time) / 1000).date()).days

        return validity_period


class InstType(Enum):
    """  产品类型
    """
    SPOT = 'SPOT'  # 币币
    MARGIN = 'MARGIN'  # 币币杠杆
    SWAP = 'SWAP'  # 永续合约
    FUTURES = 'FUTURES'  # 交割合约
    OPTION = 'OPTION'  # 期权


class State(Enum):
    """
    """
    canceled = 'canceled'  # 撤单成功
    live = 'live'  # 等待成交
    partially_filled = 'partially_filled'  # 部分成交
    filled = 'filled'  # 完全成交
    mmp_canceled = 'mmp_canceled'  # 做市商保护机制导致的自动撤单


class OrderType(Enum):
    """
    """
    market = 'market'  # 市价单
    limit = 'limit'  # 限价单
    post_only = 'post_only'  # 只做maker单
    fok = 'fok'  # 全部成交或立即取消
    ioc = 'ioc'  # 立即成交并取消剩余
    optimal_limit_ioc = 'optimal_limit_ioc'  # 市价委托立即成交并取消剩余（仅适用交割、永续）
    mmp = 'mmp'  # 做市商保护(仅适用于组合保证金账户模式下的期权订单)
    mmp_and_post_only = 'mmp_and_post_only'  # 做市商保护且只做maker单(仅适用于组合保证金账户模式下的期权订单)
    op_fok = 'op_fok'  # 期权简选（全部成交或立即取消）


class Category(Enum):
    """
    """
    normal = 'normal'  # 普通委托
    twap = 'twap'  # TWAP自动换币
    adl = 'adl'  # ADL自动减仓
    full_liquidation = 'full_liquidation'  # 强制平仓
    partial_liquidation = 'partial_liquidation'  # 强制减仓
    delivery = 'delivery'  # 交割
    ddh = 'ddh'  # 对冲减仓类型订单
    auto_conversion = 'auto_conversion'  # 抵押借币自动还币订单


class Order(BaseModel):
    """ 交易订单
    """
    inst_type: str = Field('', title='产品类型')
    inst_id: str = Field('', title='产品id')
    tgtccy: str = Field('', title='币币市价单委托数量sz的单位', description='base_ccy: 交易货币；quote_ccy：计价货币 仅适用于币币市价订单 默认买单为quote_ccy，卖单为base_ccy')
    ccy: str = Field('', title='保证金币种，适用于逐仓杠杆及合约模式下的全仓杠杆订单以及交割、永续和期权合约订单。')
    order_id: str = Field('', title='订单id')
    cl_order_id: str = Field('', title='客户自定义订单id')
    tag: str = Field('', title='订单标签')
    px: str = Field('', title='委托价格，对于期权，以币(如BTC, ETH)为单位')
    px_usd: str = Field('', title='期权价格，以USD为单位仅适用于期权，其他业务线返回空字符串')
    px_vol: str = Field('', title='期权订单的隐含波动率 仅适用于期权，其他业务线返回空字符串')
    px_type: str = Field('', title='期权的价格类型', description='px：代表按价格下单，单位为币 (请求参数 px 的数值单位是BTC或ETH) pxVol：代表按pxVol下单 pxUsd：代表按照pxUsd下单，单位为USD (请求参数px 的数值单位是USD)')
    sz: str = Field('', title='委托数量')
    pnl: str = Field('', title='收益(不包括手续费) 适用于有成交的平仓订单，其他情况均为0')
    order_type: str = Field('', title='订单类型', description='参照 OrderType 模型')
    side: str = Field('', title='订单方向')
    pos_side: str = Field('', title='持仓方向')
    td_mode: str = Field('', title='交易模式')
    acc_fillsz: str = Field('', title='累计成交数量', description='对于币币和杠杆，单位为交易货币，如 BTC-USDT, 单位为 BTC；对于市价单，无论tgtCcy是base_ccy，还是quote_ccy，单位均为交易货币；对于交割、永续以及期权，单位为张。')
    fill_px: str = Field('', title='最新成交价格', description='如果成交数量为0，该字段为""')
    trade_id: str = Field('', title='最新成交ID')
    fill_sz: str = Field('', title='最新成交数量', description='对于币币和杠杆，单位为交易货币，如 BTC-USDT, 单位为 BTC；对于市价单，无论tgtCcy是base_ccy，还是quote_ccy，单位均为交易货币；对于交割、永续以及期权，单位为张。')
    fill_time: str = Field('', title='最新成交时间')
    avg_px: str = Field('', title='成交均价', description='如果成交数量为0，该字段也为""')
    state: str = Field('', title='订单状态', description='参数 State 模型')
    lever: str = Field('', title='杠杆倍数', description='0.01到125之间的数值，仅适用于 币币杠杆/交割/永续')
    attach_algocl_ordid: str = Field('', title='下单附带止盈止损时，客户自定义的策略订单ID')
    tp_trigger_px: str = Field('', title='止盈触发价')
    tp_trigger_px_type: str = Field('', title='止盈触发价类型', description='last：最新价格 index：指数价格 mark：标记价格')
    tp_ord_px: str = Field('', title='止盈委托价')
    sl_trigger_px: str = Field('', title='止损触发价')
    sl_trigger_px_type: str = Field('', title='止损触发价类型 last：最新价格 index：指数价格 mark：标记价格')
    sl_ord_px: str = Field('', title='止损委托价')
    attach_algoords: list = Field([], title='下单附带止盈止损信息')
    linked_algoord: dict = Field({}, title='止损订单信息，仅适用于包含限价止盈单的双向止盈止损订单，触发后生成的普通订单')
    stp_dode: str = Field('', title='自成交保护模式')
    fee_ccy: str = Field('', title='手续费币种', description='对于现货和杠杆的挂单卖单，表示计价币种。其他情况下，表示收取手续费的币种')
    fee: str = Field('', title='手续费金额', description='对于现货和杠杆（除挂单卖单外）：平台收取的累计手续费，始终为负数 对于现货和杠杆的挂单卖单、交割、永续和期权：累计手续费和返佣（现货和杠杆挂单卖单始终以计价币种计算）')
    rebate_ccy: str = Field('', title='返佣币种', description='对于现货和杠杆的挂单卖单，表示交易币种。其他情况下，表示支付返佣的币种')
    rebate: str = Field('', title='返佣金额', description='仅适用于现货和杠杆 对于挂单卖单：累计手续费和返佣金额，单位为交易币种。其他情况下，表示挂单返佣金额，始终为正数，如无返佣则返回。')
    source: str = Field('', title='订单来源', description='6：计划委托策略触发后的生成的普通单 7：止盈止损策略触发后的生成的普通单 13：策略委托单触发后的生成的普通单 25：移动止盈止损策略触发后的生成的普通单 34: 追逐限价委托生成的普通单')
    category: str = Field('', title='订单种类', description='参照 Category 模型')
    reduce_only: str = Field('', title='是否只减仓', description='true 或 false')
    cancel_source: str = Field('', title='订单取消来源的原因枚举值代码')
    cancel_source_reason: str = Field('', title='订单取消来源的对应具体原因')
    quick_mgn_type: str = Field('', title='一键借币类型 仅适用于杠杆逐仓的一键借币模式', description='manual：手动 auto_borrow：自动借币 auto_repay：自动还币')
    algo_cl_ordid: str = Field('', title='客户自定义策略订单ID', description='策略订单触发，且策略单有algoClOrdId时有值，否则为""')
    algo_id: str = Field('', title='策略委托单ID 策略订单触发时有值，否则为""')
    is_tp_limit: str = Field('', title='是否为限价止盈 true 或 false.')
    utime: str = Field('', title='订单状态更新时间', description='Unix时间戳的毫秒数格式，如 1597026383085')
    ctime: str = Field('', title='订单创建时间', description='Unix时间戳的毫秒数格式，如 1597026383085')
    trade_quote_ccy: str = Field('', title='用于交易的计价币种')


class KLine(BaseModel):
    """
    """
    inst_id: str = Field('', title='产品id')
    inst_code: str = Field('', title='产品编号')
    trading_ts: str = Field('', title='交易时间')
    opening_price_fm: float = Field(0.0, title='开盘价(5M)')
    highest_price_fm: float = Field(0.0, title='最高价(5M)')
    lowest_price_fm: float = Field(0.0, title='最低价(5M)')
    closing_price_fm: float = Field(0.0, title='收盘价(5M)')
    opening_price: float = Field(0.0, title='开盘价(当日)')
    highest_price: float = Field(0.0, title='最高价(当日)')
    lowest_price: float = Field(0.0, title='最低价(当日)')
    closing_price: float = Field(0.0, title='收盘价(当日)')
    trading_vol: float = Field(0.0, title='交易量', description='以张为单位')
    trading_vol_ccy: float = Field(0.0, title='交易量', description='以币为单位')
    trading_vol_quote: float = Field(0.0, title='交易量', description='以计价货币为单位')
    confirm: str = Field('', title='K线状态 0: K线未完结 1: K线已完结')

    @property
    def trading_time(self):
        """
        :return:
        """
        if not self.trading_ts:
            return

        return dt.fromtimestamp(int(self.trading_ts) / 1000)

    @property
    def trading_date(self):
        """
        :return:
        """
        return self.trading_time.date()


class Position(BaseModel):
    """ 持仓信息
    """
    inst_type: str = Field('', title='产品类型')
    margin_model: str = Field('', title='保证金模式', description='cross(全仓)/isolated(逐仓)')
    pos_id: str = Field('', title='持仓ID')
    pos_side: str = Field('', title='持仓方向', description='long(开多)/short(开空)')
    pos: float = Field(0.0, title='持仓数量')
    average_price: float = Field(0.0, title='开仓均价')
    upl: float = Field(0.0, title='未实现收益')
    upl_ratio: float = Field(0.0, title='未实现收益率')
    upl_lastpx: float = Field(0.0, title='最新成交价未实现收益')
    upl_ratio_lastpx: float = Field(0.0, title='最新成交价未实现收益率')
    inst_id: str = Field('', title='产品id')
    lever: int = Field(1, title='杠杆倍数')
    liqpx: float = Field(0.0, title='预估强平价', description='不适用于期权')
    markpx: float = Field(0.0, title='最新标记价格')
    margin: float = Field(0.0, title='保证金余额')
    mgn_ratio: float = Field(0.0, title='维持保证金率')
    mmr: float = Field(0.0, title='维持保证金')
    trade_id: str = Field('', title='最新成交 id')
    adl: int = Field(0, title='自动减仓信号区')
    ccy: str = Field('', title='占用保证金币种')
    last: float = Field(0.0, title='最新成交价')
    idxpx: float = Field(0.0, title='最新指数价格')
    bepx: float = Field(0.0, title='盈亏平衡价')
    realized_pnl: float = Field(0.0, title='已实现收益')
    settled_pnl: float = Field(0.0, title='已结算收益')
    pnl: float = Field(0.0, title='平仓订单累计收益额(不包括手续费)')
    fee: float = Field(0.0, title='累计手续费金额，正数代表平台返佣 ，负数代表平台扣除')
    funding_fee: float = Field(0.0, title='累计资金费用')
    ctime_ts: str = Field('', title='持仓创建时间，Unix时间戳的毫秒数格式，如 1597026383085')
    utime_ts: str = Field('', title='最近一次持仓更新时间，Unix时间戳的毫秒数格式，如 1597026383085')

    def __setattr__(self, key, value):
        """
        :param key:
        :param value:
        :return:
        """
        try:
            field_type = Position.model_fields[key].annotation
        except KeyError:
            field_type = ''

        if field_type is float:
            value = float(value)
        elif field_type is int:
            value = int(value)

        super().__setattr__(key, value)

    @property
    def ctime(self):
        """
        :return:
        """
        if not self.ctime_ts:
            return

        return dt.fromtimestamp(int(self.ctime_ts) / 1000)

    @property
    def utime(self):
        """
        :return:
        """
        if not self.utime_ts:
            return

        return dt.fromtimestamp(int(self.utime_ts) / 1000)


class Okex:

    def __init__(self, flag: str = '0', certify: dict = None):
        """
        :param flag: 0: real trade, 1: simulate trade
        """
        self.flag = flag
        self.certify = certify
        if self.flag == '0' and not self.certify:
            self.certify = Config.OKEX_OPTIONS['real']
        if self.flag == '1' and not self.certify:
            self.certify = Config.OKEX_OPTIONS['simulate']

        self.domain = Config.OKEX_OPTIONS['domain']

    def get_balance(self):
        """
        :return:
        """
        account_api = AccountAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = account_api.get_account_balance()
        if rst['code'] != '0':
            err_msg = f'欧易平台对接失败: code: {rst["code"]}, err: {rst["msg"]}'
            raise Exception(err_msg)

        return rst

    @retry()
    def get_instruments(self, instType='SWAP'):
        """ 得到欧易平台当前可交易币种  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#public-data-rest-api-get-instruments 限速：20次/2s
        :param instType:
        :return:
        """
        public_api = PublicAPI(flag=self.flag, domain=self.domain, **self.certify)

        rst = public_api.get_instruments(instType=instType)
        if rst['code'] != '0':
            msg = rst['msg']
            raise BizError(message=f'欧易平台请求失败: err: {msg}')
        data = rst['data']

        ret_data = []
        for v in data:
            if v['state'] != 'live':
                continue
            # 只做USDT本币位
            if 'USDT' not in v['instId']:
                continue
            ret_data.append(v)

        return ret_data

    @retry()
    def get_kline_data(self,  instid, after='', before='',  bar='5m',  limit=300):
        """ 得到指定数字货币的日K线图  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-market-data-get-candlesticks 限速：40次/2s
        :param instid: 指定数字货币
        :param after: 在此时间戳之前的分页内容
        :param before: 再次时间戳之后的分页内容
        :param bar: 5分钟粒度
        :param limit: 指定数据条数
        :return:
        """
        try:
            market_api = MarketAPI(flag=self.flag, domain=self.domain, **self.certify)
            rst = market_api.get_candlesticks(instid, after=after, before=before, bar=bar, limit=limit)

            if rst['code'] != '0':
                msg = rst['msg']
                raise BizError(message=f'欧易平台请求失败: err: {msg}')
        except httpx.ConnectTimeout as ex:
            print(f'====================日线拉取异常  instid: {instid}')
            raise ex

        return rst['data'] or []

    @retry()
    def get_kline_data_history(self,  instid, after='', before='',  bar='5m',  limit=300):
        """ 得到指定数字货币的日K线图  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-market-data-get-candlesticks-history 限速：20次/2s
        :param instid: 指定数字货币
        :param after: 在此时间戳之前的分页内容
        :param before: 再次时间戳之后的分页内容
        :param bar: 5分钟粒度
        :param limit: 指定数据条数
        :return:
        """
        market_api = MarketAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = market_api.get_history_candlesticks(instid, after=after, before=before, bar=bar, limit=limit)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    @retry()
    def place_order(self, inst_id, px, sz, pos_side, side='',
                    trade_mode='isolated',
                    cl_order_id='',
                    order_type='limit',
                    **kwargs):
        """ 委托下单  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-trade  限速：60次/2s
        :param inst_id: 产品id
        :param px: 委托价格
        :param sz: 委托数量
        :param pos_side: long(开多)/short(开空)
        :param trade_mode:
        :param cl_order_id: 用户自定义订单id
        :param side: buy(买)/sell(卖)
        :param order_type: 限价
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, debug=True, **self.certify)
        rst = trade_client.place_order(instId=inst_id, px=px, sz=sz,
                                       tdMode=trade_mode,
                                       clOrdId=cl_order_id,
                                       side=side,
                                       ordType=order_type,
                                       posSide=pos_side,
                                       reduceOnly="false",
                                       **kwargs)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    @retry()
    def get_order(self, inst_id, order_id, cl_order_id):
        """ 获取订单信息 # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-trade-get-order-details
        :param inst_id:
        :param order_id:
        :param cl_order_id: 用户自定义订单id
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = trade_client.get_order(instId=inst_id, ordId=order_id, clOrdId=cl_order_id)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    @retry()
    def place_algo_order(self, inst_id, trigger_px, order_px, sz,
                         side, pos_side,
                         trade_mode='isolated',
                         order_type='trigger',
                         trigger_px_type='mark',
                         **kwargs):
        """ 计划委托下单  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-algo-trading-post-place-algo-order  限速：20次/2s
        :param inst_id: 产品id
        :param order_px: 委托价格
        :param trigger_px: 触发价格
        :param sz: 委托数量
        :param pos_side: long(开多)/short(开空)
        :param trade_mode:
        :param side: buy(买)/sell(卖)
        :param order_type: 限价
        :param trigger_px_type: 计划委托触发价格类型
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, debug=True, **self.certify)
        rst = trade_client.place_algo_order(instId=inst_id, orderPx=order_px, sz=sz, triggerPx=trigger_px,
                                            tdMode=trade_mode,
                                            side=side,
                                            ordType=order_type,
                                            posSide=pos_side,
                                            triggerPxType=trigger_px_type,
                                            **kwargs)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst

    @retry()
    def get_algo_order(self, algo_id):
        """ 获取计划委托下单信息 # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-algo-trading-get-algo-order-details
        :param algo_id:
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = trade_client.get_algo_order_details(algoId=algo_id)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    def cancel_algo_order(self, inst_id, algo_id):
        """ 撤销委托下单 # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#order-book-trading-algo-trading-post-cancel-algo-order
        :param inst_id:
        :param algo_id:
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = trade_client.cancel_algo_order(params=[{'instId': inst_id, 'algoId': algo_id}])
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    @retry()
    def get_convert_contract_coin(self, inst_id, sz: str, px: str):
        """ 张币转换
        :param inst_id:
        :param sz: 数量，币转张时，为币的数量，张转币时，为张的数量。
        :param px: 委托价格
        :param
        :return:
        """
        public_client = PublicAPI(flag=self.flag, domain=self.domain, **self.certify)
        rst = public_client.get_convert_contract_coin(type='1', instId=inst_id, sz=sz, px=px, unit='usds')
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        return rst['data'] or []

    @retry()
    def get_positions(self, inst_type='SWAP', inst_id='', pos_id='') -> list[Position]:
        """ 获取当前持仓信息  # todo 接口文档地址: https://www.okx.com/docs-v5/zh/#trading-account-rest-api-get-positions
        :param inst_type:
        :param inst_id:
        :param pos_id:
        :return:
        """
        account_client = AccountAPI(flag=self.flag, domain=self.domain, debug=True, **self.certify)
        rst = account_client.get_positions(instType=inst_type, instId=inst_id, posId=pos_id)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])

        positions = []
        for rec in rst['data'] or []:
            position = Position()
            position.pos_id = rec['posId']
            position.inst_type = rec['instType']
            position.margin_model = rec['mgnMode']
            position.pos_side = rec['posSide']
            position.pos = rec['pos']
            position.average_price = rec['avgPx']
            position.upl = rec['upl']
            position.upl_ratio = rec['uplRatio']
            position.upl_ratio_lastpx = rec['uplLastPx']
            position.inst_id = rec['instId']
            position.lever = rec['lever']
            position.liqpx = rec['liqPx']
            position.markpx = rec['markPx']
            position.margin = rec['margin']
            position.mgn_ratio = rec['mgnRatio']
            position.trade_id = rec['tradeId']
            position.ccy = rec['ccy']
            position.last = rec['last']
            position.idxpx = rec['idxPx']
            position.bepx = rec['bePx']
            position.realized_pnl = rec['realizedPnl']
            position.pnl = rec['pnl']
            position.fee = rec['fee']
            position.funding_fee = rec['fundingFee']
            position.ctime_ts = rec['cTime']
            position.utime_ts = rec['uTime']
            positions.append(position)

        return positions

    @retry()
    def close_position(self, inst_id, pos_side: str, margin_model: str, ccy: str):
        """ 市价平掉指定交易产品的持仓
        :param inst_id:
        :param pos_side:
        :param margin_model:
        :param ccy:
        :return:
        """
        trade_client = TradeAPI(flag=self.flag, domain=self.domain, debug=True, **self.certify)
        rst = trade_client.close_positions(instId=inst_id, posSide=pos_side, mgnMode=margin_model, ccy=ccy)
        if rst['code'] != '0':
            raise OkexException(code=rst['code'], msg=rst['msg'])


def get_decimal_places(value: str):
    """
    :param value:
    :return:
    """
    value_split = value.split('.')
    if len(value_split) == 2:
        return len(value_split[1])
    else:
        # 默认一位小数
        return 1


def main():
    """
    :return:
    """
    # # 从历史日K线中
    # now_timestamp = dt.now().timestamp()
    # after = str(int(now_timestamp) * 1000)
    # data = Okex().get_kline_data_history(instid='BTC-USDT-SWAP', after=after)
    # for rec in data:
    #     print(dt.fromtimestamp(int(rec[0]) / 1000), rec)

    # # 下单
    # order_px = '109750'
    # dec_places = get_decimal_places(order_px)
    # trigger_px = round(int(order_px) + int(order_px) * 0.0001, dec_places)
    #
    import json
    okex_client = Okex(flag='0')
    insts = okex_client.get_instruments


    # lots = okex_client.get_convert_contract_coin(inst_id='BTC-USDT-SWAP', sz='100', px=order_px)
    #
    # data = okex_client.place_algo_order(inst_id='BTC-USDT-SWAP', trigger_px=trigger_px, order_px='109750', sz=str(lots[0]['sz']),
    #                                     side='sell', pos_side='short')
    # print(data)

    # 委托计划订单信息
    # algo_id = '2988408595659776000'
    # data = okex_client.get_algo_order(algo_id=algo_id)
    # print(json.dumps(data[0], ensure_ascii=False, indent=4))
    # positions = okex_client.get_positions()
    # for pos in positions:
    #     okex_client.close_position(inst_id=pos.inst_id, pos_side=pos.pos_side, margin_model=pos.margin_model, ccy=pos.ccy)
    # # print(json.dumps(rst[0], ensure_ascii=False, indent=4))


if __name__ == "__main__":

    main()



